package admin

import (
	"fmt"
	"goProject/api/auth"
	"goProject/db"
	"goProject/table"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"gitee.com/ruige_fun/util/rlog"
	"gorm.io/gorm"

	"gitee.com/ruige_fun/util/std"
	"github.com/kataras/iris/v12"
)

type pGetUserList struct {
	std.ListParams
	Username string `json:"username"` //用户名，* 通配符
}

// getUserList 获取用户列表
func getUserList(c iris.Context) {
	var p pGetUserList
	err := c.ReadQuery(&p)
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, "参数校验失败", nil, nil))
		return
	}
	var result = make([]table.User, 0)
	var total int64
	wh := db.MySQL

	if p.ID > 0 {
		wh = wh.Where("`id` = ?", p.ID)
	}
	if p.Username != "" {
		if strings.Contains(p.Username, `*`) {
			p.Username = strings.ReplaceAll(p.Username, "*", `%`)
			wh = wh.Where("`username` LIKE ?", p.Username)
		} else {
			wh = wh.Where("`username` = ?", p.Username)
		}
	}
	wh.Model(&table.User{}).Offset(-1).Limit(-1).Count(&total)
	wh.Offset((p.Page - 1) * p.Size).Limit(p.Size).Preload("Profile.Role").Order("`id` DESC").Find(&result)
	c.JSON(std.NewResp(http.StatusOK, "", result, total))
}

// getUserRoleList 获取我可以授权的所有角色列表
func getUserRoleList(c iris.Context) {
	var result []table.Role
	roleID, _ := c.Values().GetInt(fmt.Sprint(c.GetID()))
	if fmt.Sprint(c.GetID()) != "1" {
		db.MySQL.Where("`id` > ?", roleID).Find(&result)
	} else {
		db.MySQL.Find(&result)
	}
	c.JSON(std.NewResp(http.StatusOK, "", result, len(result)))
}

type pGetUserCoinHistory struct {
	ID uint `json:"id" validate:"required,min=1"`
}

// getUserCoinHistoryByID 获取指定用户的积分变更记录
func getUserCoinHistoryByID(c iris.Context) {
	var p pGetUserCoinHistory
	err := c.ReadQuery(&p)
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, "参数校验失败", nil, nil))
		return
	}
	var result = make([]table.CoinHistory, 0)
	db.MySQL.Where("`user_id` = ?", p.ID).Order("`id` DESC").Find(&result)
	c.JSON(std.NewResp(http.StatusOK, "", result, nil))
}

type pUpdateCoin struct {
	ID    uint    `json:"id" validate:"required,min=1"`
	Coin  float64 `json:"coin"`
	Intro string  `json:"intro"`
}

func updateCoin(c iris.Context) {
	var p pUpdateCoin
	err := c.ReadJSON(&p)
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, "参数校验失败", nil, nil))
		return
	}
	err = db.MySQL.Transaction(func(tx *gorm.DB) error {
		var u table.Profile
		err2 := tx.Where("`id` = ?", p.ID).First(&u).Error
		if err2 != nil {
			rlog.Error("积分充值失败：", err2)
			return fmt.Errorf("充值失败，获取该账号的记录失败。")
		}

		//插入充值记录
		cmdUserID, _ := strconv.Atoi(fmt.Sprint(c.GetID()))
		item := table.CoinHistory{
			UserID:    u.ID,
			Coin:      p.Coin,
			Type:      1,
			Intro:     p.Intro,
			CmdUserID: uint(cmdUserID),
		}
		if p.Coin >= 0 {
			item.Type = 1
		} else {
			item.Type = 2
		}
		err2 = tx.Create(&item).Error
		if err2 != nil {
			rlog.Error("积分充值失败：", err2)
			return fmt.Errorf("充值失败，保存该账号的充值记录失败。")
		}

		//保存充值后的积分
		u.Coin += p.Coin
		err2 = tx.Where("`id` = ?", u.ID).Select("Coin").Updates(&u).Error
		if err2 != nil {
			rlog.Error("积分充值失败：", err2)
			return fmt.Errorf("充值失败，保存该账号的记录失败。")
		}
		return nil
	})
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, fmt.Sprint(err), nil, nil))
		return
	}
	rlog.Success("【积分充值成功】：", fmt.Sprintf("管理员【%v】给用户【%v】充值了【%f】个积分：%v", c.GetID(), p.ID, p.Coin, p.Intro))
	c.JSON(std.NewResp(http.StatusOK, "", nil, nil))
}

type pUpdateUserSetting struct {
	ID     uint   `json:"id" validate:"required,min=1"`
	VIP    int    `json:"vip" validate:"required,min=1"`
	Name   string `json:"name"`
	Lock   int    `json:"lock" validate:"required,min=1"`
	RoleID uint   `json:"role_id" validate:"required,min=1"`
}

// updateUserSetting 基本设置
func updateUserSetting(c iris.Context) {
	var p pUpdateUserSetting
	err := c.ReadJSON(&p)
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, "参数校验失败", nil, nil))
		return
	}
	var u table.User
	err = db.MySQL.Where("`id` = ?", p.ID).Preload("Profile").First(&u).Error
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, "查找账号失败", nil, nil))
		return
	}
	var temp = u

	if fmt.Sprint(c.GetID()) != "1" { //1用户，有最高权限；
		roleID, _ := auth.Role.Get(fmt.Sprint(c.GetID())) //获取自己的权限ID
		if u.Profile.RoleID <= uint(roleID) {
			//如果对方权限，比自己的更高，那就不修改锁定状态和权限角色
			p.Lock = u.Lock
			p.RoleID = u.Profile.RoleID
		}
		if p.RoleID <= uint(roleID) {
			//如果授权的权限比自己更高或者一样，那就不修改权限角色
			//除了 1 用户，其它用户都只能授权比自己低的权限角色
			p.RoleID = u.Profile.RoleID
		}
	}
	u.Lock = p.Lock
	u.Vip = p.VIP
	u.AdminName = p.Name
	if u.ID == 1 {
		u.Lock = 1   //1用户，禁止修改锁定状态；1用户，永远正常。
		p.RoleID = 1 //1用户，禁止被修改权限角色；1用户，永远是ROOT用户。
	} else {
		if p.Lock != u.Lock { //账号锁定状态被更改
			_ = auth.Token.Del(fmt.Sprint(u.ID)) //删除掉现有的登录token
		}
	}
	err = db.MySQL.Transaction(func(tx *gorm.DB) error {
		err2 := tx.Select("RoleID").Where("`id` = ?", u.ID).Updates(&table.Profile{
			RoleID: p.RoleID,
		}).Error
		if err2 != nil {
			return fmt.Errorf("修改权限角色失败")
		}
		err2 = tx.Select("Lock", "Vip", "AdminName").Where("`id` = ?", u.ID).Updates(&u).Error
		if err2 != nil {
			return fmt.Errorf("保存设置失败")
		}
		return nil
	})
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, fmt.Sprint(err), nil, nil))
		return
	}
	u.Profile = nil
	temp.Profile = nil
	rlog.Success("设置用户属性：管理员", c.GetID(), "设置了用户", u.ID, "的属性信息", fmt.Sprintf("%+v", u), "原来属性", fmt.Sprintf("%+v", temp))
	_ = auth.Role.Set(fmt.Sprint(u.ID), int64(p.RoleID)) //更新一下该用户的权限信息
	c.JSON(std.NewResp(http.StatusOK, "", nil, nil))
}

type pGetUserRoleMenuByRoleID struct {
	ID uint `json:"id" validate:"required,min=1"`
}

// getUserRoleMenuByRoleID 获取指定权限角色的菜单列表，只能看，不能改。
func getUserRoleMenuByRoleID(c iris.Context) {
	var p pGetUserRoleMenuByRoleID
	err := c.ReadQuery(&p)
	if err != nil {
		c.JSON(std.NewResp(http.StatusBadRequest, "参数校验失败", nil, nil))
		return
	}

	if p.ID <= 2 {
		var result = make([]table.MenuDir, 0)
		db.MySQL.Preload("Items").Find(&result)

		if p.ID == 1 {
			c.JSON(std.NewResp(http.StatusOK, "", result, len(result)))
			return
		} else if p.ID == 2 {
			c.JSON(std.NewResp(http.StatusOK, "", result[1:], len(result)-1))
			return
		}
	}

	var result = make([]table.MenuDir, 0)
	db.MySQL.Where("`id` > ?", 2).Preload("Items").Find(&result)

	var allItem []table.RoleMenuItem //获取当前角色，拥有的所有菜单项（页面）
	db.MySQL.Where("`role_id` = ?", p.ID).Find(&allItem)
	var have = sync.Map{} //记录当前角色，拥有的菜单项（页面）ID
	for _, d := range allItem {
		have.Store(fmt.Sprint(d.MenuItemID), byte(0))
	}

	var tempResult = make([]table.MenuDir, 0)
	for i := 0; i < len(result); i++ {
		var temp = table.MenuDir{
			ID:    result[i].ID,
			Path:  result[i].Path,
			Icon:  result[i].Icon,
			Label: result[i].Label,
			Items: nil,
			Sort:  result[i].Sort,
		}
		for j := 0; j < len(result[i].Items); j++ {
			if _, ok := have.Load(fmt.Sprint(result[i].Items[j].ID)); ok {
				temp.Items = append(temp.Items, result[i].Items[j])
			}
		}
		if len(temp.Items) > 0 {
			tempResult = append(tempResult, temp)
		}
	}
	c.JSON(std.NewResp(http.StatusOK, "", tempResult, len(tempResult)))
}
